<?php

namespace App\Services;

use Carbon\Carbon;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Log;

class IpBlacklistService
{
    protected $blacklistFile;
    protected $whitelistFile;
    protected $logFile;

    public function __construct()
    {
        $this->blacklistFile = storage_path('app/ip_blacklist.txt');
        $this->whitelistFile = storage_path('app/ip_whitelist.txt');
        $this->logFile = storage_path('logs/ip_access.log');
        $this->ensureFilesExist();
    }

    /**
     * 确保必要的文件存在
     */
    protected function ensureFilesExist()
    {
        $files = [
            $this->blacklistFile,
            $this->whitelistFile
        ];
        
        foreach ($files as $file) {
            if (!File::exists($file)) {
                File::put($file, '');
            }
        }
        
        if (!File::exists(dirname($this->logFile))) {
            File::makeDirectory(dirname($this->logFile), 0755, true);
        }
    }

    /**
     * 检查 IP 是否在白名单中
     */
    public function isWhitelisted($ip)
    {
        if (!File::exists($this->whitelistFile)) {
            return false;
        }

        $content = File::get($this->whitelistFile);
        $lines = explode("\n", trim($content));
        
        foreach ($lines as $line) {
            if (empty(trim($line))) continue;
            
            if (trim($line) === $ip) {
                return true;
            }
        }

        return false;
    }

    /**
     * 添加 IP 到白名单
     */
    public function addToWhitelist($ip)
    {
        if ($this->isWhitelisted($ip)) {
            return false;
        }
        
        File::append($this->whitelistFile, $ip . "\n");
        Log::info("IP {$ip} 已添加到白名单");
        
        return true;
    }

    /**
     * 从白名单中移除 IP
     */
    public function removeFromWhitelist($ip)
    {
        if (!File::exists($this->whitelistFile)) {
            return false;
        }

        $content = File::get($this->whitelistFile);
        $lines = explode("\n", trim($content));
        
        $updatedLines = [];
        $removed = false;

        foreach ($lines as $line) {
            if (empty(trim($line))) continue;
            
            if (trim($line) !== $ip) {
                $updatedLines[] = $line;
            } else {
                $removed = true;
            }
        }

        File::put($this->whitelistFile, implode("\n", $updatedLines) . "\n");
        
        if ($removed) {
            Log::info("IP {$ip} 已从白名单中移除");
        }
        
        return $removed;
    }

    /**
     * 获取所有白名单 IP
     */
    public function getWhitelist()
    {
        if (!File::exists($this->whitelistFile)) {
            return [];
        }

        $content = File::get($this->whitelistFile);
        $lines = explode("\n", trim($content));
        
        $whitelist = [];
        foreach ($lines as $line) {
            if (!empty(trim($line))) {
                $whitelist[] = trim($line);
            }
        }

        return $whitelist;
    }

    /**
     * 检查 IP 是否在黑名单中（排除白名单）
     */
    public function isBlacklisted($ip)
    {
        // 白名单 IP 直接通过
        if ($this->isWhitelisted($ip)) {
            return false;
        }

        if (!File::exists($this->blacklistFile)) {
            return false;
        }

        $content = File::get($this->blacklistFile);
        $lines = explode("\n", trim($content));
        
        $currentTime = Carbon::now()->timestamp;
        $isBlacklisted = false;
        $updatedLines = [];

        foreach ($lines as $line) {
            if (empty(trim($line))) continue;
            
            list($listedIp, $expireTime) = explode('|', $line);
            
            // 如果已过期，跳过该条目
            if ($expireTime < $currentTime) {
                continue;
            }
            
            // 如果找到匹配的 IP
            if ($listedIp === $ip) {
                $isBlacklisted = true;
            }
            
            $updatedLines[] = $line;
        }

        // 更新文件，移除过期条目
        if (count($lines) !== count($updatedLines)) {
            File::put($this->blacklistFile, implode("\n", $updatedLines) . "\n");
        }

        return $isBlacklisted;
    }

    /**
     * 添加 IP 到黑名单
     */
    public function addToBlacklist($ip, $expireMinutes = 60)
    {
        // 如果 IP 在白名单中，不加入黑名单
        if ($this->isWhitelisted($ip)) {
            Log::warning("尝试将白名单 IP {$ip} 加入黑名单，操作被拒绝");
            return false;
        }

        $expireAt = Carbon::now()->addMinutes($expireMinutes)->timestamp;
        $entry = "{$ip}|{$expireAt}\n";
        
        File::append($this->blacklistFile, $entry);
        
        Log::warning("IP {$ip} 已被加入黑名单，过期时间: " . Carbon::createFromTimestamp($expireAt));
        
        return true;
    }

    /**
     * 从黑名单中移除 IP
     */
    public function removeFromBlacklist($ip)
    {
        if (!File::exists($this->blacklistFile)) {
            return true;
        }

        $content = File::get($this->blacklistFile);
        $lines = explode("\n", trim($content));
        
        $updatedLines = [];
        $removed = false;

        foreach ($lines as $line) {
            if (empty(trim($line))) continue;
            
            list($listedIp, $expireTime) = explode('|', $line);
            
            if ($listedIp !== $ip) {
                $updatedLines[] = $line;
            } else {
                $removed = true;
            }
        }

        File::put($this->blacklistFile, implode("\n", $updatedLines) . "\n");
        
        if ($removed) {
            Log::info("IP {$ip} 已从黑名单中移除");
        }
        
        return $removed;
    }

    /**
     * 记录访问日志
     */
    public function logAccess($ip, $path, $status = 'normal', $userAgent = null)
    {
        $timestamp = Carbon::now()->toDateTimeString();
        $userAgent = $userAgent ?: request()->userAgent();
        $logEntry = "[{$timestamp}] {$ip} - {$path} - {$status} - {$userAgent}\n";
        
        File::append($this->logFile, $logEntry);
    }

    /**
     * 获取所有有效的黑名单 IP
     */
    public function getActiveBlacklist()
    {
        if (!File::exists($this->blacklistFile)) {
            return [];
        }

        $content = File::get($this->blacklistFile);
        $lines = explode("\n", trim($content));
        
        $currentTime = Carbon::now()->timestamp;
        $activeIps = [];

        foreach ($lines as $line) {
            if (empty(trim($line))) continue;
            
            list($ip, $expireTime) = explode('|', $line);
            
            if ($expireTime >= $currentTime) {
                $expireDate = Carbon::createFromTimestamp($expireTime);
                $activeIps[$ip] = [
                    'expire_at' => $expireDate->toDateTimeString(),
                    'remaining' => $expireDate->diffForHumans()
                ];
            }
        }

        return $activeIps;
    }

    /**
     * 获取所有黑名单 IP（包括过期的）
     */
    public function getAllBlacklist()
    {
        if (!File::exists($this->blacklistFile)) {
            return [];
        }

        $content = File::get($this->blacklistFile);
        $lines = explode("\n", trim($content));
        
        $allIps = [];

        foreach ($lines as $line) {
            if (empty(trim($line))) continue;
            
            list($ip, $expireTime) = explode('|', $line);
            $expireDate = Carbon::createFromTimestamp($expireTime);
            $isExpired = $expireTime < Carbon::now()->timestamp;
            
            $allIps[$ip] = [
                'expire_at' => $expireDate->toDateTimeString(),
                'is_expired' => $isExpired,
                'remaining' => $isExpired ? '已过期' : $expireDate->diffForHumans()
            ];
        }

        return $allIps;
    }

    /**
     * 清理过期的黑名单条目
     */
    public function cleanupExpired()
    {
        if (!File::exists($this->blacklistFile)) {
            return 0;
        }

        $content = File::get($this->blacklistFile);
        $lines = explode("\n", trim($content));
        
        $currentTime = Carbon::now()->timestamp;
        $updatedLines = [];
        $removedCount = 0;

        foreach ($lines as $line) {
            if (empty(trim($line))) continue;
            
            list($ip, $expireTime) = explode('|', $line);
            
            if ($expireTime >= $currentTime) {
                $updatedLines[] = $line;
            } else {
                $removedCount++;
            }
        }

        File::put($this->blacklistFile, implode("\n", $updatedLines) . "\n");
        
        if ($removedCount > 0) {
            Log::info("清理了 {$removedCount} 个过期的黑名单条目");
        }
        
        return $removedCount;
    }

    /**
     * 检查并自动封禁异常 IP
     */
    public function autoBanForException($ip, $exception, $banMinutes = null)
    {
        $banMinutes = $banMinutes ?: config('ip_blacklist.ban_duration', 60);
        
        // 根据异常类型决定是否封禁
        $shouldBan = $this->shouldBanForException($exception);
        
        if ($shouldBan) {
            $this->addToBlacklist($ip, $banMinutes);
            $this->logAccess($ip, request()->path(), 'auto_banned: ' . get_class($exception));
            
            return true;
        }
        
        return false;
    }

    /**
     * 判断异常是否需要封禁 IP
     */
    protected function shouldBanForException($exception)
    {
        $banExceptions = config('ip_blacklist.ban_exceptions', [
            \Illuminate\Auth\AuthenticationException::class,
            \Illuminate\Auth\Access\AuthorizationException::class,
            \Symfony\Component\HttpKernel\Exception\HttpException::class,
        ]);

        foreach ($banExceptions as $banException) {
            if ($exception instanceof $banException) {
                return true;
            }
        }

        return false;
    }

    /**
     * 获取访问日志统计
     */
    public function getAccessStats($hours = 24)
    {
        if (!File::exists($this->logFile)) {
            return [];
        }

        $content = File::get($this->logFile);
        $lines = explode("\n", trim($content));
        
        $sinceTime = Carbon::now()->subHours($hours)->timestamp;
        $stats = [
            'total' => 0,
            'by_ip' => [],
            'by_status' => [],
            'by_path' => []
        ];

        foreach ($lines as $line) {
            if (empty(trim($line))) continue;
            
            // 解析日志行 [timestamp] ip - path - status - userAgent
            preg_match('/\[(.*?)\] (\S+) - (\S+) - (\S+) - (.*)/', $line, $matches);
            
            if (count($matches) >= 5) {
                $timestamp = $matches[1];
                $ip = $matches[2];
                $path = $matches[3];
                $status = $matches[4];
                
                $logTime = Carbon::parse($timestamp)->timestamp;
                
                if ($logTime >= $sinceTime) {
                    $stats['total']++;
                    
                    // IP 统计
                    $stats['by_ip'][$ip] = ($stats['by_ip'][$ip] ?? 0) + 1;
                    
                    // 状态统计
                    $stats['by_status'][$status] = ($stats['by_status'][$status] ?? 0) + 1;
                    
                    // 路径统计
                    $stats['by_path'][$path] = ($stats['by_path'][$path] ?? 0) + 1;
                }
            }
        }

        // 排序
        arsort($stats['by_ip']);
        arsort($stats['by_status']);
        arsort($stats['by_path']);

        return $stats;
    }

    /**
     * 清空黑名单
     */
    public function clearBlacklist()
    {
        if (File::exists($this->blacklistFile)) {
            File::put($this->blacklistFile, '');
            Log::info("黑名单已清空");
            return true;
        }
        return false;
    }

    /**
     * 清空白名单
     */
    public function clearWhitelist()
    {
        if (File::exists($this->whitelistFile)) {
            File::put($this->whitelistFile, '');
            Log::info("白名单已清空");
            return true;
        }
        return false;
    }
}
